package com.hoe.tsb.fraft.client.role;

import com.hoe.tsb.Configuration;
import com.hoe.tsb.fraft.client.ClientRoleBridge;
import com.hoe.tsb.fraft.enums.RoleType;
import com.hoe.tsb.fraft.event.msg.Canvass;
import com.hoe.tsb.fraft.event.msg.FRaftMessage;
import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * 候选者角色
 * </p>
 *
 * @author hoe
 * @version 1.0
 * @date 2022/12/5 16:23
 */
@Slf4j
public class Candidate extends SupportRole {

    /**
     * 当前已拉票数
     */
    private int mVotedCount = 0;

    public Candidate(ClientRoleBridge bridge, Configuration configuration, RoleObserver roleObserver) {
        super(bridge, configuration, roleObserver);
    }

    @Override
    public void onTimeout() {
        //超时后自动切换为Follower
        turnTo(RoleType.FOLLOWER);
    }

    @Override
    public void onRoleTurn() {
        //已拉票数清零（自己给自己先投一票）
        mVotedCount = 1;
        //广播拉票消息
        Canvass canvass = new Canvass();
        canvass.setTerm(mRoleObserver.getTerm());
        canvass.setMaxLogIndex(mRoleObserver.getMaxIndex());
        mBridge.broadcast(canvass);
    }

    @Override
    public boolean handleMessage(FRaftMessage msg) {
        if (super.handleMessage(msg)) {
            return true;
        }

        //无论任何消息，进行新Leader判断
        checkHasLeader(msg);

        switch (msg.getType()) {
            /*
             * 投票消息
             */
            case VOTE:
                //单线程调用，不用考虑并发问题
                mVotedCount++;
                if (mVotedCount > mBridge.getNodeCount() / 2) {
                    turnTo(RoleType.LEADER);
                }
                return true;
        }

        return false;
    }

    /**
     * 校验是否已经存在Leader了<br/>
     * 校验逻辑是判断消息的发送者是否是Leader，任期是否大于或等于当前任期
     * @param msg 接收到的消息
     */
    private void checkHasLeader(FRaftMessage msg) {
        if (msg.getRoleType() == RoleType.LEADER && msg.getTerm() >= mRoleObserver.getTerm()) {
            log.info("已经产生了新的Leader，直接回滚到Follower，新Leader ip：{}，port：{}", msg.getNodes().get(0).getIp(), msg.getNodes().get(0).getPort());
            //已经产生了Leader，回退到Follower
            turnTo(RoleType.FOLLOWER);
        }
    }

}
